


import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

import javax.naming.ldap.StartTlsRequest;

import svg.Container;
import svg.JobCanvas;
import svg.JobViewer;
import svg.TaskCanvas;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.io.GraphMLFile;

public class Simulator {

	/**
	 * @param args
	 * @throws Exception 
	 */

	public static ArrayList<Task> simulate(DataGenerator dataGen) throws Exception {

		ArrayList<Task> tasks = dataGen.getTasks(); 
		ArrayList<Job> jobs = dataGen.getAllJobs();

		int lcm = dataGen.getLCM();

		for(Task task : tasks)
		{
			//task.setPriority(lcm - lcm / task.getPeriod());
		}


		int numberOfCycles = 1 * lcm;
		Job lastJob = null;	//last job served

		//Simulate
		for(int i = 0; i < numberOfCycles; i++) {
			Job currentJob = null;
			for(Job job : jobs){
				//serve job that is released and has highest priority
				System.out.println(job);
				if(job.getRelease() <= i && (currentJob == null || compareJobs(job, currentJob))) {
					currentJob = job;
				}
			}
			
		

			if(currentJob != null){

				//Start serving a new job - last job is preempted
				if(!currentJob.equals(lastJob) && lastJob != null) 
				{
					currentJob.addStartCompTime(i);
					lastJob.addFinishCompTime(i);
				}else if(!currentJob.equals(lastJob) && lastJob==null){
					currentJob.addStartCompTime(i);
				}
					

				
				if(currentJob.getStart() == -1){
					currentJob.setStart(i);
				}

				if(currentJob.getTime() != 0) {
					currentJob.setTime(currentJob.getTime() - 1);
				}

				//Job is finish being served
				if(currentJob.getTime() == 0) {
					
					currentJob.addFinishCompTime(i);

					currentJob.setResponse(i - currentJob.getStart());

					if(currentJob.getOwner().getWcrt() < currentJob.getResponse()) {

						currentJob.getOwner().setWcrt(currentJob.getResponse());
					}

					jobs.remove(currentJob);
				}
				lastJob=currentJob;
			}
		}

		for(Task task : tasks) {

			//System.out.println(task.toString());
			for(Job job : task.getJobs()) {

				//System.out.println(job.toString());
			}
		}

		visualizeSchedule(tasks);
		
		return tasks;

	}

	// if j1 has a higher priority than j2
	private static boolean compareJobs(Job j1, Job j2)
	{
		
		if(j1.getOwner().getPriority() < j2.getOwner().getPriority())
		{
			return true;
		}

		if(j1.getOwner().getPriority() == j2.getOwner().getPriority())
		{
			if(j1.getOwner().getName().compareToIgnoreCase(j2.getOwner().getName()) > 0)
			{
				return true;
			}
			if(j1.getOwner().getName().compareToIgnoreCase(j2.getOwner().getName()) == 0)
			{
				throw new RuntimeException("Two tasks have the same name and period! Are they the same one task?..");
			}
		}

		return false;
	}

	private static void visualizeSchedule(ArrayList<Task> tasks) throws Exception 
	{
		//Specify graph values
		// create JobViewer
		JobViewer jobViewer = new JobViewer(600, 600, "diagram");

		// create BufferedImage and Graphics controller
		BufferedImage image = new BufferedImage(jobViewer.getWidth(), 
				jobViewer.getHeight(), BufferedImage.TYPE_INT_ARGB);
		Graphics2D graphics = image.createGraphics();
		JobViewer.setGraphicsQuality(graphics);
		graphics.setColor(Color.WHITE);
		graphics.fillRect(0, 0, jobViewer.getWidth(), jobViewer.getHeight());

		// create main panel
		Container mainPanel = new Container(10, 40, 
				jobViewer.getWidth() - 10 - 10, 
				jobViewer.getHeight() - 40 - 20);

		//Specify values according to the task set
		String name = "Task ";

		int numberOfTasks = tasks.size();

		// create tasks and jobs
		for(int i = 0; i < numberOfTasks; i++)
		{
			Task task = tasks.get(i);
			
			TaskCanvas taskPanel = new TaskCanvas(name + (i + 1), graphics, 60, task.getPeriod(), task.getDeadline(), 15);

			
			for (Job job : task.getJobs())	//TODO: Is all job scheduled? Maybe do it until reach scheduling end time.
			{
				ArrayList<Integer> startCompTimes = job.getStartCompTimes();
				ArrayList<Integer> finishCompTimes = job.getFinishCompTimes();
				
				if (!(startCompTimes.size()==finishCompTimes.size())){
					throw new Exception(
							"Mismatch between number of start and end executing times: " +
							"Job started being executed " + startCompTimes.size() + 
							" and ended being executed " + finishCompTimes.size());
				} else {
					for(int j = 0 ; j < startCompTimes.size(); j++)
					{
						int sct = startCompTimes.get(j);
						int fct = finishCompTimes.get(j);
						JobCanvas jobPanel = new JobCanvas(sct, fct-sct, taskPanel);
						taskPanel.getJobs().add(jobPanel);
					}
				}
				
			
			
			}

			mainPanel.getElements().add(taskPanel);
		}

		

		// layout everything
		mainPanel.layout(5);

		// make image
		jobViewer.generateImage("My Fancy Embedded Systems", "test.png", 
				mainPanel, image, graphics);
	}



}
